using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Threading;
using System.Windows.Forms;
using System.IO;

namespace LogAnalyzer.Grabbers
{
    public class FileGrabber : GrabberBase
    {
        //private long _firstReadBufferSize = 102400;
        private long _firstReadBufferSize = 0;
        private bool _firstRead = true;
        private FileSystemWatcher _fsWatcher;
        private DateTime _lastUpdate = new DateTime(0);
        private long _lastReadPosition = 0;
        private FileStream _fs;
        private string _choosenFileName = null;
        Encoding _enc = null;


        public override DialogResult ShowConfigDialog()
        {
            using (Dialogs.FileGrabberCfg cfg = new LogAnalyzer.Grabbers.Dialogs.FileGrabberCfg())
            {
                if (!string.IsNullOrEmpty(FileName))
                {
                    cfg.FileName = FileName;
                }
                cfg.Encoding = Encoding;
                cfg.BufferSize = _firstReadBufferSize;

                DialogResult dlgRes = cfg.ShowDialog();
                
                if (dlgRes == DialogResult.OK)
                {
                    FileName = cfg.FileName;
                    Encoding = cfg.Encoding;
                    _firstReadBufferSize = cfg.BufferSize;
                }
                return dlgRes;
            }
        }
        

        protected override void StartGrab(bool isRestart)
        {
            if (isRestart)
            {
                _lastReadPosition = 0;
                FireClearViewerEvent();
            }

            _choosenFileName = null;
            string fileToOpen = "";


            if (File.Exists(FileName))
            {
                fileToOpen = FileName;
            }
            else
            {
                if (Directory.Exists(FileName))
                {
                    using (Dialogs.ChooseFileInFolder frm = new LogAnalyzer.Grabbers.Dialogs.ChooseFileInFolder(FileName))
                    {
                        if (frm.ShowDialog() == DialogResult.OK)
                        {
                            fileToOpen = frm.FileName;
                            _choosenFileName = new FileInfo(fileToOpen).Name;
                        }
                        else
                        {
                            HandleNewString(">>> No file selected, grabber didn't start!\r\n\r\n");
                            return;
                        }
                    }
                }
                else
                {
                    MessageBox.Show(
                        Globalization.ResourceManager.Current.GetString("FILE_OR_FOLDER_NOT_FOUND"),
                        Globalization.ResourceManager.Current.GetString("ERROR"),
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }


            if (_fs == null)
                _fs = new FileStream(fileToOpen, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 1, true);

            _firstRead = true;

            switch (Encoding)
            {
                case DataEncoding.ASCII:
                    _enc = System.Text.Encoding.ASCII;
                    break;
                case DataEncoding.BigEndianUnicode:
                    _enc = System.Text.Encoding.BigEndianUnicode;
                    break;
                case DataEncoding.Unicode:
                    _enc = System.Text.Encoding.Unicode;
                    break;
                case DataEncoding.UTF32:
                    _enc = System.Text.Encoding.UTF32;
                    break;
                case DataEncoding.UTF7:
                    _enc = System.Text.Encoding.UTF7;
                    break;
                case DataEncoding.UTF8:
                    _enc = System.Text.Encoding.UTF8;
                    break;
                default:
                    _enc = System.Text.Encoding.Default;
                    break;
            }

            if (_fsWatcher == null)
            {
                int lastSlashIdx = fileToOpen.LastIndexOf('\\');
                string directory = fileToOpen.Substring(0, lastSlashIdx);
                string file = fileToOpen.Substring(lastSlashIdx + 1);
                _fsWatcher = new FileSystemWatcher(directory, file);
                _fsWatcher.NotifyFilter = NotifyFilters.Size;
                _fsWatcher.EnableRaisingEvents = true;
                _fsWatcher.Changed += new FileSystemEventHandler(_fsWatcher_Changed);

                FileChanged();
            }
        }
        public override void StopGrab()
        {
            //StopTimer();

            if (_fsWatcher != null)
            {
                _fsWatcher.Dispose();
                _fsWatcher = null;
            }

            if (_fs != null)
            {
                _fs.Close();
                _fs.Dispose();
                _fs = null;
            }
        }
        
        
        private void _fsWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            FileChanged();
        }        
        private void FileChanged()
        {
            //TimeSpan intervalFromLastUpdate = DateTime.Now.Subtract(_lastUpdate);
            //if (intervalFromLastUpdate.TotalSeconds < 1)
            //    return;

            //_lastUpdate = DateTime.Now;

            //StopTimer();

            HandleNewString(GetDiff());

            //StartTimer();
        }
        private string GetDiff()
        {
            string diff = "";

            /// if last read position is after total file length, re-initialize 
            /// last read position to zero
            /// 
            if (_fs.Length < _lastReadPosition)
            {
                _lastReadPosition = 0;
            }

            /// if first block to read is greater than "first read buffer size"
            /// move _lastReadPosition forwar to excluse previous bytes
            /// 
            if (_firstRead)
            {
                _firstRead = false;
                if (_fs.Length - _lastReadPosition > _firstReadBufferSize)
                {
                    _lastReadPosition = _fs.Length - _firstReadBufferSize;
                }
            }

            _fs.Position = _lastReadPosition;
            int lenght = (int)(_fs.Length - _lastReadPosition);
            byte[] buffer = new byte[lenght];
            _fs.Read(buffer, 0, lenght);

            string tmpDiff = _enc.GetString(buffer, 0, lenght);

            _lastReadPosition += tmpDiff.Length;
            diff += tmpDiff;

            return diff;
        }


        #region Backup timer

        //private void StartTimer()
        //{
        //    if (_tmr != null)
        //        return;

        //    _tmr = new System.Threading.Timer(new TimerCallback(
        //        delegate(Object o)
        //        {
        //            FileChanged();
        //        }),
        //        null,
        //        10000, Timeout.Infinite);
        //}
        //private void StopTimer()
        //{
        //    if (_tmr != null)
        //    {
        //        _tmr.Dispose();
        //        _tmr = null;
        //    }
        //}

        #endregion



        public override void Dispose()
        {
            StopGrab();
        }


        private string FileName
        {
            get 
            {
                string file = "";
                if (Config.ContainsKey("fileGrabber.fileName"))
                    file = Config["fileGrabber.fileName"];
                return file;
            }
            set 
            {
                if (Config.ContainsKey("fileGrabber.fileName"))
                    Config.Remove("fileGrabber.fileName");
                Config["fileGrabber.fileName"] = value;
            }
        }

        private DataEncoding Encoding
        {
            get
            {
                DataEncoding enc = DataEncoding.UTF8;
                if (Config.ContainsKey("fileGrabber.encoding"))
                    try
                    {
                        enc = (DataEncoding)Enum.Parse(typeof(DataEncoding), Config["fileGrabber.encoding"]);
                    }
                    catch { }
                return enc;
            }
            set
            {
                if (Config.ContainsKey("fileGrabber.encoding"))
                    Config.Remove("fileGrabber.encoding");
                Config["fileGrabber.encoding"] = value.ToString();
            }
        }   

        public override string TextForViewer
        {
            get 
            {
                if (_choosenFileName != null)
                    return Path.Combine(FileName, _choosenFileName);
                else
                    return FileName;
            }
        }

    }
}
